package com.leyou.cart.service;

import com.leyou.LyCartApplication;
import com.leyou.cart.entity.Cart;
import com.leyou.common.auth.pojo.UserInfo;
import com.leyou.common.auth.utils.UserHolder;
import com.leyou.common.constants.LyConstants;
import com.leyou.common.exception.LyException;
import com.leyou.common.exception.enums.ExceptionEnum;
import com.leyou.common.utils.JsonUtils;
import com.leyou.item.client.ItemClient;
import com.leyou.item.entity.Sku;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Service
public class CartService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private ItemClient itemClient;


    /**
     * 添加商品到购物车中
     *
     * @param cart 购物车对象接收参数
     */
    public void addCart(Cart cart) {
        // 1、获取当前用户信息
        UserInfo user = UserHolder.getUser();
        if (user == null) {
            throw new LyException(ExceptionEnum.UNAUTHORIZED);
        }
        // 2、拼接第一层Key
        String key = LyConstants.CART_PRE + user.getId();
        // 3、从redis中取出值
        BoundHashOperations<String, String, String> hashOps = redisTemplate.boundHashOps(key);
        // 4、判断是否存在这个sku
        // 4.1 skuId : 第二层key
        String skuId = cart.getSkuId().toString();
        // 4.2 如果已经存在更新数量即可
        if (hashOps.hasKey(skuId)) {
            // 改数量
            String cacheCart = hashOps.get(skuId);
            // 转成对象
            Cart oldCart = JsonUtils.toBean(cacheCart, Cart.class);
            // 修改数量
            cart.setNum(oldCart.getNum() + cart.getNum());
        }
        // 5、更新到redis
        hashOps.put(skuId, JsonUtils.toString(cart));
    }

    /**
     * 获取购物车列表
     *
     * @return
     */
    public List<Cart> findCartList() {
        // 1、获取当前用户信息
        UserInfo user = UserHolder.getUser();
        if (user == null) {
            throw new LyException(ExceptionEnum.UNAUTHORIZED);
        }
        // 2、拼接第一层Key
        String key = LyConstants.CART_PRE + user.getId();
        // 3、判断购物车是否存在
        if (!redisTemplate.hasKey(key)) {
            throw new LyException(ExceptionEnum.CARTS_NOT_FOUND);
        }
        // 4、获取对象返回
        BoundHashOperations<String, String, String> hashOps = redisTemplate.boundHashOps(key);
        // 5、获取值:  取出所有的value
        List<String> carts = hashOps.values();
        if (CollectionUtils.isEmpty(carts)) {
            throw new LyException(ExceptionEnum.CARTS_NOT_FOUND);
        }
        // 6、把字符串转成对象
        List<Cart> cartList = carts.stream().map(c -> JsonUtils.toBean(c, Cart.class)).collect(Collectors.toList());

        //            =======================================
        for (Cart cart : cartList) {
            // 6.1 根据skuId查询到sku
            Sku skuById = itemClient.findSkuById(cart.getSkuId());
            Long onePrice = skuById.getPrice();
            //计算总价并封装
            cart.setNewPrice(onePrice * cart.getNum());
        }
        System.out.println("cartLongHashMap = " + cartList.toString());
        // 7、返回
        return cartList;
    }

    /**
     * 批量添加购物车
     *
     * @param cartList
     */
    public void addCartList(List<Cart> cartList) {
        // 批量添加购物车信息： 问题？ 在for循环中操作redis
        /*for (Cart cart : cartList) {
            addCart(cart);
        }*/

        // 1、获取当前用户信息
        UserInfo user = UserHolder.getUser();
        if (user == null) {
            throw new LyException(ExceptionEnum.UNAUTHORIZED);
        }
        // 2、拼接第一层Key
        String key = LyConstants.CART_PRE + user.getId();

        // 在redis中有一个管道： Pipeline： 可以封装多次请求一次性到达 redis中
        redisTemplate.executePipelined(new RedisCallback<List<Cart>>() {
            @Override
            public List<Cart> doInRedis(RedisConnection connection) throws DataAccessException {
                // 打开管道
                connection.openPipeline();
                // 迭代参数，去做批处理
                for (Cart cart : cartList) {
                    try {
                        // 获取字符串
                        byte[] bytes = connection.hGet(key.getBytes(), cart.getSkuId().toString().getBytes());
                        if (bytes != null) {
                            String json = new String(bytes, "UTF-8");
                            Cart cacheCart = JsonUtils.toBean(json, Cart.class);
                            // 修改数量
                            cart.setNum(cart.getNum() + cacheCart.getNum());
                        }
                        String cartStr = JsonUtils.toString(cart);
                        // 把购物车设置进去
                        connection.hSet(key.getBytes(), cart.getSkuId().toString().getBytes(), cartStr.getBytes());
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                }
                return null;
            }
        });
    }

    /**
     * 修改用户的购物车商品数量
     *
     * @param skuId skuId
     * @param num   商品数量
     * @return 无
     */
    public void updateCart(Long skuId, Integer num) {
        // 1.获取当前用户信息
        UserInfo user = UserHolder.getUser();
        if (user == null) {
            throw new LyException(ExceptionEnum.UNAUTHORIZED);
        }

        // 2.拼接第一层key
        String key = LyConstants.CART_PRE + user.getId();

        // 3.判断购物车是否存在
        if (!redisTemplate.hasKey(key)) {
            throw new LyException(ExceptionEnum.CARTS_NOT_FOUND);
        }

        // 4.根据skuId取出商品
        BoundHashOperations<String, String, String> hashOps = redisTemplate.boundHashOps(key);
        String hashKey = skuId.toString();
        // 判空
        if (!hashOps.hasKey(hashKey)) {
            throw new LyException(ExceptionEnum.CARTS_NOT_FOUND);
        }
        // 改数量
        String cacheCart = hashOps.get(hashKey);
        Cart cart = JsonUtils.toBean(cacheCart, Cart.class);
        cart.setNum(num);
        // 5.更新到redis
        hashOps.put(hashKey, JsonUtils.toString(cart));
    }

    /**
     * 根据skuId删除用户购物车商品
     *
     * @param skuId skuId
     * @return 无
     */
    public void deleteCart(String skuId) {
        // 1.获取当前用户信息
        UserInfo user = UserHolder.getUser();
        if (user == null) {
            throw new LyException(ExceptionEnum.UNAUTHORIZED);
        }

        // 2.拼接第一层key
        String key = LyConstants.CART_PRE + user.getId();

        // 3.判断购物车是否存在
        if (!redisTemplate.hasKey(key)) {
            throw new LyException(ExceptionEnum.CARTS_NOT_FOUND);
        }

        // 执行删除
        Long count = redisTemplate.opsForHash().delete(key, skuId);
        if (count != 1) {
            throw new LyException(ExceptionEnum.DELETE_OPERATION_FAIL);
        }


        // // 4.根据skuId取出商品
        // BoundHashOperations<String, String, String> hashOps = redisTemplate.boundHashOps(key);
        // String hashKey = skuId.toString();
        // // 判空
        // if (!hashOps.hasKey(hashKey)) {
        //     throw new LyException(ExceptionEnum.CARTS_NOT_FOUND);
        // }
        //
        // // 5.根据skuId删除商品
        // Long delete = hashOps.delete(hashKey);
        // if (delete != 1) {
        //     throw new LyException(ExceptionEnum.DELETE_OPERATION_FAIL);
        // }
    }

    /*
     * 删除用户的购物车的商品
     * xiaoChenChen写的代码
     * */
    public void deleteSku(Long skuId) {
        //1.获取当前用户信息
        UserInfo user = UserHolder.getUser();
        // 2、拼接第一层Key
        String key = LyConstants.CART_PRE + user.getId();
        //3.从redis中删除该商品
        HashOperations<String, String, String> hash = redisTemplate.opsForHash();
        hash.delete(key, skuId.toString());
    }


    /**
     * 创建订单后根据批量删除购物车
     *
     * @param messageMap
     */
    public void deleteCartBySkuIds(Map<String, List<Long>> messageMap) {
        // 1.获取异步操作用户id
        String mapKey = messageMap.keySet().iterator().next();
        String key = LyConstants.CART_PRE + mapKey;
        List<Long> skuIds = messageMap.get(mapKey);

        // 3.判断购物车是否存在
        if (!redisTemplate.hasKey(key)) {
            throw new LyException(ExceptionEnum.CARTS_NOT_FOUND);
        }

        // 执行删除
        // for (Long skuId : skuIds) {
        //     Long count = redisTemplate.opsForHash().delete(key, skuId.toString());
        //     if (count != 1) {
        //         throw new LyException(ExceptionEnum.DELETE_OPERATION_FAIL);
        //     }
        // }
        redisTemplate.executePipelined(new RedisCallback<List<Cart>>() {
            @Override
            public List<Cart> doInRedis(RedisConnection connection) throws DataAccessException {
                // 打开管道
                connection.openPipeline();
                // 迭代删除
                for (Long skuId : skuIds) {
                    byte[] bytes = skuId.toString().getBytes();
                    connection.hDel(key.getBytes(), bytes);
                }
                return null;
            }
        });
    }

    /*
     * 删除用户选中商品
     * xiaoChenChen写的代码
     * */
    public void deleteChooseSku(String ids) {
        //1.获取当前用户信息
        UserInfo user = UserHolder.getUser();
        // 2、拼接第一层Key
        String key = LyConstants.CART_PRE + user.getId();
        //3.从redis中删除该商品
        HashOperations<String, String, String> hash = redisTemplate.opsForHash();
        String[] split = ids.split(",");
        if (split.length < 1) {
            throw new LyException(ExceptionEnum.DELETE_OPERATION_FAIL);
        }
        for (String s : split) {
            hash.delete(key, s);
        }
    }



}
